﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Text;
using System.IO;
using System.Xml;
using System.Collections.Generic;

namespace GeoSketch2.Core
{
    /// <summary>
    /// The different styles of lines
    /// </summary>
    public enum LineStyle
    {
        /// <summary>
        /// A solid line
        /// </summary>
        Solid,
        /// <summary>
        /// A dotted line
        /// </summary>
        Dot,
        /// <summary>
        /// A dashed line
        /// </summary>
        Dash
    }

    /// <summary>
    /// The LineType object
    /// </summary>
    [Serializable]
    public class LineType
    {
        #region XMLElementsName
#pragma warning disable 1591
        const string XML_Id = "Id";
        const string XML_Style = "Style";
        const string XML_Width = "Width";
        const string XML_Scale = "Scale";
#pragma warning restore 1591
        #endregion

        #region Fields
        /// <summary>
        /// The style of the line
        /// </summary>
        public LineStyle Style;

        /// <summary>
        /// The width of the line (pixels)
        /// </summary>
        public float Width;

        /// <summary>
        /// The scale of the line
        /// </summary>
        public float Scale;

        /// <summary>
        /// If true the line type is the layer's one
        /// </summary>
         //bool IsByLayer;

        public int Id;
        #endregion

        #region Constructor
        /// <summary>
        /// The type of the line
        /// </summary>
        public LineType()
            : this(LineStyle.Solid, 1f, 1f)
        {
        }

        /// <summary>
        /// The type of the line
        /// </summary>
        /// <param name="LineStyle">The style of the line</param>
        public LineType(LineStyle LineStyle)
            :this(LineStyle,1f,1f)
        {
        }

        /// <summary>
        /// The type of the line
        /// </summary>
        /// <param name="LineStyle">The style of the line</param>
        /// <param name="Width">The width of the line (pixels)</param>
        /// <param name="Scale">The scale of the line</param>
        public LineType(LineStyle LineStyle, float Width, float Scale)
        :this(LineStyle,Width,Scale,Vars.Setup.StandardObjects.LineType.NextAvailableId)
        {
            Vars.Setup.StandardObjects.LineType.NextAvailableId++;
        }
        /// <summary>
        /// The type of the line
        /// </summary>
        /// <param name="LineStyle">The style of the line</param>
        /// <param name="Width">The width of the line (pixels)</param>
        /// <param name="Scale">The scale of the line</param>
        /// <param name="Id">The id of the linetype</param>
        public LineType(LineStyle LineStyle, float Width, float Scale, int Id)
        {
            this.Style = LineStyle;
            this.Width = Width;
            this.Scale = Scale;
            this.Id = Id;
        }

        /// <summary>
        /// The type of the line
        /// </summary>
        /// <param name="Xr">The XmlReader to read from</param>
        public LineType(XmlReader Xr)
        {
            Xr.ReadToFollowing(XML_Id);
            this.Id = Convert.ToInt32(Xr.ReadString(), Vars.Setup.GeoSketch.NumberFormat);

            Xr.ReadToFollowing(XML_Style);
            this.Style = (LineStyle)Enum.Parse(typeof(LineStyle), Xr.ReadString());

            Xr.ReadToFollowing(XML_Width);
            this.Width = Convert.ToSingle(Xr.ReadString(), Vars.Setup.GeoSketch.NumberFormat);

            Xr.ReadToFollowing(XML_Scale);
            this.Scale = Convert.ToSingle(Xr.ReadString(), Vars.Setup.GeoSketch.NumberFormat);

            Xr.ReadEndElement();
        }
        #endregion

        #region Methods
        /// <summary>
        /// The string representation of the object
        /// </summary>
        public override string ToString()
        {
            return Style.ToString()+" - Width : "+Width+" - Scale : "+Scale;
        }

        /// <summary>
        /// Writes the object to a file
        /// </summary>
        /// <param name="Xw">The XmlWriter to write to</param>
        public void ToFile(XmlWriter Xw)
        {
            Xw.WriteStartElement(this.GetType().FullName);

            Xw.WriteStartElement(XML_Id);
            Xw.WriteString(Id.ToString(Vars.Setup.GeoSketch.NumberFormat));
            Xw.WriteEndElement();

            Xw.WriteStartElement(XML_Style);
            Xw.WriteString(Style.ToString());
            Xw.WriteEndElement();

            Xw.WriteStartElement(XML_Width);
            Xw.WriteString(Width.ToString(Vars.Setup.GeoSketch.NumberFormat));
            Xw.WriteEndElement();

            Xw.WriteStartElement(XML_Scale);
            Xw.WriteString(Scale.ToString(Vars.Setup.GeoSketch.NumberFormat));
            Xw.WriteEndElement();

            Xw.WriteEndElement();
        }

        /// <summary>
        /// Gets a bitmap with the overview of the linetype
        /// </summary>
        /// <param name="Size">The size of the bitmap to create</param>
        public Bitmap ImageOverview(Size Size)
        {
            Bitmap dst = new Bitmap(Size.Width - 2, Size.Height - 2);
            Graphics g = Graphics.FromImage(dst);

            Pen p = new Pen(Color.Black, Width);
            if (Style != LineStyle.Solid)
            {
                p.DashStyle = DashStyle.Custom;
                p.DashPattern = DashPattern;
            }

            g.DrawLine(p, 0, dst.Height / 2, dst.Width, dst.Height / 2);

            return dst;
        }

        public void ToDXFR13(TextWriter Tw)
        {
            Tw.WriteLine("0");
            Tw.WriteLine("LTYPE");

            Tw.WriteLine("2");
            Tw.WriteLine(this.Id.ToString(Core.Vars.Setup.GeoSketch.NumberFormat));

            Tw.WriteLine("70");
            Tw.WriteLine("0");

            Tw.WriteLine("3");
            Tw.WriteLine(this.DXFR13DescriptionString);

            Tw.WriteLine("72");
            Tw.WriteLine("65");

            Tw.WriteLine("73");
            Tw.WriteLine(this.DashPattern.Length.ToString(Core.Vars.Setup.GeoSketch.NumberFormat));

            Tw.WriteLine("40");
            if (this.Style == LineStyle.Solid)
            {
                Tw.WriteLine("0.0");
            }
            else
            {
                float[] dashpattern = this.DashPattern;
                double dashpatternlength=0;
                foreach (float f in dashpattern)
                {
                    dashpatternlength += f;
                }
                Tw.WriteLine(dashpatternlength.ToString(Core.Vars.Setup.GeoSketch.NumberFormat));

                for(int i=0;i<dashpattern.Length;i++)
                {
                    Tw.WriteLine("49");
                    if (i % 2 == 0)
                    {
                        if (dashpattern[i] == Scale)
                        {
                            Tw.WriteLine("0.0");
                        }
                        else
                        {
                            Tw.WriteLine(dashpattern[i].ToString(Core.Vars.Setup.GeoSketch.NumberFormat));
                        }
                    }
                    else
                    {
                        Tw.WriteLine((dashpattern[i]*-1d).ToString(Core.Vars.Setup.GeoSketch.NumberFormat));
                    }
                }
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the pattern of the custom line, if not solid
        /// </summary>
        public float[] DashPattern
        {
            get
            {
                if (Style == LineStyle.Dash)
                {
                    return new float[]{
                        Vars.Setup.StandardObjects.LineType.DashLength*Scale,
                        Vars.Setup.StandardObjects.LineType.DashSpaceLength*Scale
                    };
                }
                else if (Style == LineStyle.Dot)
                {
                    return new float[]{
                        Width,
                        Vars.Setup.StandardObjects.LineType.DotSpaceLength*Scale
                    };
                }
                else
                {
                    return new float[0];
                }
            }
        }

        /// <summary>
        /// Gets the toolstrip menu item of the linetype to add it to an interface
        /// </summary>
        public ToolStripMenuItem MenuItem
        {
            get
            {
                ToolStripMenuItem item = new ToolStripMenuItem();

                item.AutoSize = true;
                
                item.BackColor = Color.White;
                item.DisplayStyle = ToolStripItemDisplayStyle.Text;
                item.Width = 100;
                item.Tag = this;
                item.Paint += new PaintEventHandler(LineTypeMenuItemPaint);

                return item;
            }
        }

        void LineTypeMenuItemPaint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImage(ImageOverview(((ToolStripMenuItem)sender).ContentRectangle.Size), ((ToolStripMenuItem)sender).ContentRectangle.Location);
        }

        string DXFR13DescriptionString
        {
            get
            {
                return this.Id.ToString(Core.Vars.Setup.GeoSketch.NumberFormat);
            }
        }
        #endregion
    }
}
